#include "stdafx.h"
#include "Application.h"

#include "View.h"
#include "ControllerManager.h"

namespace
{
	#define MAX_LOADSTRING 100

	HINSTANCE	s_hInst;
	TCHAR		szTitle[MAX_LOADSTRING];
	TCHAR		szWindowClass[MAX_LOADSTRING];

	INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
	{
		UNREFERENCED_PARAMETER(lParam);
		switch (message)
		{
		case WM_INITDIALOG:
			return (INT_PTR)TRUE;

		case WM_COMMAND:
			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
			{
				EndDialog(hDlg, LOWORD(wParam));
				return (INT_PTR)TRUE;
			}
			break;
		}
		return (INT_PTR)FALSE;
	}

}

namespace Cinetic
{
    View*               g_view = nullptr;
    ControllerManager*  g_controller_manager = nullptr;

	View&	application_view()
	{
        ME_ASSERT(g_view != nullptr, "Application doesn't have a view");
		return *g_view;
	}

	ControllerManager&	application_controller_manager()
	{
		ME_ASSERT(g_controller_manager != nullptr, "Application doesn't have a view");
		return *g_controller_manager;
	}

	Application::Application() :
		m_finished(false)
	{

	}

	int Application::run()
	{
		MSG msg;
		HACCEL hAccelTable;

		s_hInst = GetModuleHandle(0);

		LoadString(s_hInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
		LoadString(s_hInst, IDC_CINETIC, szWindowClass, MAX_LOADSTRING);
		register_window_class();

		if (!create_window())
		{
			return FALSE;
		}

		hAccelTable = LoadAccelerators(s_hInst, MAKEINTRESOURCE(IDC_CINETIC));

		init_subsystems();
        on_init();

		while (!m_finished) {
			while( PeekMessage(&msg, m_hWnd, 0, 0, PM_REMOVE)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			m_renderer->draw();
		}


		return (int) msg.wParam;
	}

	bool Application::create_window()
	{
		m_hWnd = CreateWindowEx(0, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, s_hInst, this);

		if (!m_hWnd)
		{
			return false;
		}

		ShowWindow(m_hWnd, SW_SHOWNORMAL);
		UpdateWindow(m_hWnd);

		return true;
	}

	void Application::init_subsystems()
	{
		m_renderer.reset(new Cinetic::Renderer(m_hWnd, s_hInst));
		m_scene.reset(new Scene());
        m_scene->attach(m_renderer.get());
		g_view = m_renderer.get();
		g_controller_manager = this;
	}

	LRESULT CALLBACK Application::StaticWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
	{
		Application* app;

		// Get pointer to window
		if(uMsg == WM_CREATE)
		{
			app = (Application*)((LPCREATESTRUCT)lParam)->lpCreateParams;
			SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)app);
		}
		else
		{
			app = (Application*)GetWindowLongPtr(hWnd,GWL_USERDATA);
			if(!app) return DefWindowProc(hWnd,uMsg,wParam,lParam);
		}

		app->m_hWnd = hWnd;
		return app->WndProc(uMsg,wParam,lParam);
	}

	LRESULT Application::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
	{
		int wmId, wmEvent;

		switch (message)
		{
		case WM_COMMAND:
			wmId    = LOWORD(wParam);
			wmEvent = HIWORD(wParam);

			switch (wmId)
			{
			case IDM_ABOUT:
				DialogBox(s_hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), m_hWnd, About);
				break;
			case IDM_EXIT:
				DestroyWindow(m_hWnd);
				m_finished = true;
				break;
			default:
				return DefWindowProc(m_hWnd, message, wParam, lParam);
			}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			m_finished = true;
			break;
		default:
			return DefWindowProc(m_hWnd, message, wParam, lParam);
		}
		return 0;
	}

	ATOM Application::register_window_class()
	{
		WNDCLASSEX wcex;

		wcex.cbSize = sizeof(WNDCLASSEX);

		wcex.style			= CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc	= StaticWndProc;
		wcex.cbClsExtra		= 0;
		wcex.cbWndExtra		= 0;
		wcex.hInstance		= s_hInst;
		wcex.hIcon			= LoadIcon(s_hInst, MAKEINTRESOURCE(IDI_CINETIC));
		wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
		wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
		wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_CINETIC);
		wcex.lpszClassName	= szWindowClass;
		wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

		return RegisterClassEx(&wcex);
	}

	void Application::on_init()
	{
	}

	void SteerApplication::on_init()
	{
		m_scene->add_static_model("Sinbad.mesh");
	}

}